package code.HAOJianguo;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import java.util.Iterator;

import code.Najib.ActivityAgentNetDiscovery;

import client.domainModels.Node.Node;
import client.domainModels.NodeImpl.AbstractNode;
import client.domainModels.NodeImpl.LogFile;
import client.domainModels.NodeImpl.Receiver;

public class DelegationModel {

	private static ArrayList<String> PROPOSAL = new ArrayList<String>() {
		{
			add("request");
			add("propose");

		};
	};
	private static ArrayList<String> REJECT_PROPOSAL = new ArrayList<String>() {
		{
			add("reject");
			add("refuse");
		};
	};
	private static ArrayList<String> ACCEPT_PROPOSAL = new ArrayList<String>() {
		{
			add("accept");
			add("agree");
		};
	};

	/*
	 * This is a container of all the actors and participants. Each agent is
	 * unique.
	 */
	private static ArrayList<String> agents;

	/**
	 * @author HAO Jianguo This is a function to analyse all the activity of
	 *         contract net protocol.
	 * */
	public static void analyseProposeInteraction(LogFile log) {
		agents = new ArrayList<String>();
		int agentAmount = getAgentAmount(log);
		ArrayList[][] interactionMatrix = getProposeInteractionMatrix(log,
				agentAmount);

		// final matrix
		Integer[][] netDrawMatrix = new Integer[agentAmount][agentAmount];
		// initialisation
		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				netDrawMatrix[i][j] = 0;
			}
		}

		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				// either element is null -> all of two are not satisfact
				// propose
				if (interactionMatrix[i][j] == null
						|| interactionMatrix[j][i] == null) {
					continue;
				} else {
					// one is propose
					for (int k = 0; k < interactionMatrix[i][j].size(); k++) {
						InteractionMap im = (InteractionMap) interactionMatrix[i][j]
								.get(k);
						if (PROPOSAL.contains(im.getPerformative()
								.toLowerCase())) {
							// another is accept or reject -> one is satisfact
							// propose
							String conversationOfActor = im.getConversation();
							for (int l = 0; l < interactionMatrix[j][i].size(); l++) {
								if (existSatisfactEvent(ACCEPT_PROPOSAL,
										interactionMatrix[j][i],
										conversationOfActor)
										|| existSatisfactEvent(REJECT_PROPOSAL,
												interactionMatrix[j][i],
												conversationOfActor)) {
									netDrawMatrix[i][j] += 1;
									break;
								}
							}

						}
					}

				}
			}
		}
		/********** TEST ********/
		for (int i = 0; i < agentAmount; i++) {
			for (int j = 0; j < agentAmount; j++) {
				System.out.print(netDrawMatrix[i][j]);
			}
			System.out.println();
		}
		/**********************/
		createFileVNA(netDrawMatrix, "./propose_interaction.vna");
		createBatchFile("./batch_propose.txt", "propose_interaction.vna");
	}

	private static int getAgentAmount(LogFile log) {
		int agentAmount = 0;
		String[] nodes = log.getChildNodeNames();
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<AbstractNode> events = case_
						.getChildNames_childObjs().get("Event");
				for (Iterator<AbstractNode> iii = events.iterator(); iii
						.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<AbstractNode> actors = event
							.getChildNames_childObjs().get("Actor");
					ArrayList<AbstractNode> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					// The collection (agents) of actor and receivers is empty
					// or
					// not
					String actorID = actors.get(0).getID();
					if (agents.isEmpty()) {
						// add actor to the collection
						agents.add(actorID);
					} else {
						if (!agents.contains(actorID)) {
							agents.add(actorID);
						}
					}
					// add each receiver to the collection
					ArrayList<AbstractNode> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						if (!agents.contains(receiverName)) {
							agents.add(receiverName);
						}
					}
				}
			}
		}
		// create a matrix and the size of matrix is amount of agent * amount of
		// agent.
		agentAmount = agents.size();
		return agentAmount;
	}

	// public static int getPerformatifAmount(LogFile log) {
	// int caseAmount = 0;
	// String[] nodes = log.getChildNodeNames();
	// // Get leaves nodes of root node.
	// for (int i = 0; i < nodes.length; i++) {
	// // name of root node's leaves nodes.
	// String root_leaf = nodes[i];
	// // get cases - root node's leaves nodes.
	// ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
	// // iterate cases and get his leaves nodes'object.
	// for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
	// // get each event - cases' leaves nodes object.
	// Node case_ = ii.next();
	// ArrayList<AbstractNode> events = case_.getChildNames_childObjs().get(
	// "Event");
	// for (Iterator<AbstractNode> iii = events.iterator(); iii.hasNext();) {
	// Node event = iii.next();
	// // get actor, receivers - event's leaves nodes.
	// ArrayList<AbstractNode> actors = event.getChildNames_childObjs()
	// .get("Actor");
	// ArrayList<AbstractNode> performative = event
	// .getChildNames_childObjs().get("Performative");
	// // The collection (agents) of actor and receivers is empty
	// // or
	// // not
	// String actorID = actors.get(0).getID();
	// if (agents.isEmpty()) {
	// // add actor to the collection
	// agents.add(actorID);
	// } else {
	// if (!agents.contains(actorID)) {
	// agents.add(actorID);
	// }
	// }
	// // add each receiver to the collection
	// ArrayList<AbstractNode> receivers = receiverss.get(0)
	// .getChildNames_childObjs().get("Receiver");
	// for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
	// .hasNext();) {
	// Node receiver = iiii.next();
	// String receiverName = receiver.getID();
	// if (!agents.contains(receiverName)) {
	// agents.add(receiverName);
	// }
	// }
	// }
	// }
	// caseAmount = cases.size();
	// }
	// // create a matrix and the size of matrix is amount of agent * amount of
	// // agent.
	// return caseAmount;
	// }

	/**
	 * This foncion will get a matrix which contains all the interaction in the
	 * file log. Each line of the matrix is an actor, and each row of the matrix
	 * is a receiver.
	 * 
	 * @author HAO Jianguo
	 * @param log
	 *            The object of LogFile to analyse.
	 * @param agentAmount
	 *            The amount of agent(actor, participant).
	 * @return interactionMatrix The matrix which contains all the interaction
	 *         in the file log.
	 * */
	private static ArrayList[][] getProposeInteractionMatrix(LogFile log,
			int agentAmount) {
		ArrayList<InteractionMap>[][] interactionMatrix = new ArrayList[agentAmount][agentAmount];
		String[] nodes = log.getChildNodeNames();
		// Part 2 - analyse the matrix of delegate
		// Get leaves nodes of root node.
		for (int i = 0; i < nodes.length; i++) {
			// name of root node's leaves nodes.
			String root_leaf = nodes[i];
			// get cases - root node's leaves nodes.
			ArrayList<AbstractNode> cases = log.getChildNodes(root_leaf);
			// iterate cases and get his leaves nodes'object.
			for (Iterator<AbstractNode> ii = cases.iterator(); ii.hasNext();) {
				// get each event - cases' leaves nodes object.
				Node case_ = ii.next();
				ArrayList<AbstractNode> events = case_
						.getChildNames_childObjs().get("Event");
				for (Iterator<AbstractNode> iii = events.iterator(); iii
						.hasNext();) {
					Node event = iii.next();
					// get actor, receivers - event's leaves nodes.
					ArrayList<AbstractNode> actors = event
							.getChildNames_childObjs().get("Actor");
					ArrayList<AbstractNode> performative = event
							.getChildNames_childObjs().get("Performatif");
					ArrayList<AbstractNode> conversations = event
							.getChildNames_childObjs().get("Conversation");
					ArrayList<AbstractNode> receiverss = event
							.getChildNames_childObjs().get("Receivers");
					ArrayList<AbstractNode> receivers = receiverss.get(0)
							.getChildNames_childObjs().get("Receiver");
					// The collection (agents) of actor and receivers is empty
					// or not
					String actorID = actors.get(0).getID();
					int indexOfActor = agents.indexOf(actorID);

					// iterate each receiver to the collection
					for (Iterator<AbstractNode> iiii = receivers.iterator(); iiii
							.hasNext();) {
						Node receiver = iiii.next();
						String receiverName = receiver.getID();
						int indexOfReceiver = agents.indexOf(receiverName);
						// add
						if (interactionMatrix[indexOfActor][indexOfReceiver] == null) {
							interactionMatrix[indexOfActor][indexOfReceiver] = new ArrayList<InteractionMap>();
						}
						String performatif = performative.get(0).getID();
						String conversation = conversations.get(0).getID();
						interactionMatrix[indexOfActor][indexOfReceiver]
								.add(new InteractionMap(performatif,
										conversation));
					}
				}
			}
		}
		return interactionMatrix;
	}

	/**
	 * This fonction will create a VNA file to be used in NetDraw
	 * 
	 * @author HAO Jianguo
	 * */
	public static void createFileVNA(Integer[][] matrix, String filePath) {
		File pointVNA = new File(filePath);
		try {
			FileWriter fw = new FileWriter(pointVNA);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("*Node data" + "\n");
			bw.write("*Node properties" + "\n");
			bw.write("*Tie data" + "\n");
			bw.write("ACTOR RECEIVER \"" + "Propose Interaction" + "\"" + "\n");
			for (int i = 0; i < matrix.length; i++) {
				for (int j = 0; j < matrix.length; j++) {
					if (matrix[i][j] != 0) {
						String actor = agents.get(i);
						String receiver = agents.get(j);
						bw.write("\"" + actor + "\"");
						bw.write(" ");
						bw.write("\"" + receiver + "\"");
						bw.write(" ");
						bw.write("" + matrix[i][j] + "");
						bw.write("\n");
					}
				}
			}
			bw.flush();
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void createBatchFile(String filePath, String vnaName) {
		File pointBatch = new File(filePath);
		// String nameOfFile = "";
		// if (filePath.contains("/")) {
		// StringTokenizer st = new StringTokenizer(filePath, "/");
		//
		// while (st.hasMoreTokens()) {
		// nameOfFile = st.nextToken();
		// }
		// } else if (filePath.contains("\\")) {
		// StringTokenizer st = new StringTokenizer(filePath, "\\");
		// while (st.hasMoreTokens()) {
		// nameOfFile = st.nextToken();
		// }
		// }

		try {
			FileWriter fw = new FileWriter(pointBatch);
			BufferedWriter bw = new BufferedWriter(fw);
			bw.write("Loadvna " + vnaName + "\n");
			bw.write("runlayout" + "\n");
			bw.flush();
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static boolean existSatisfactEvent(ArrayList<String> keywords,
			ArrayList<InteractionMap> im, String conversation) {
		for (int i = 0; i < im.size(); i++) {
			if (keywords.contains(im.get(i).getPerformative())
					&& im.get(i).getConversation()
							.equalsIgnoreCase(conversation)) {
				return true;
			}
		}
		return false;
	}
}
